// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.

namespace Microsoft.Samples.Commerce.Order.CommerceEntities
{
    using Microsoft.Commerce.Contracts;

    /// <summary>
    /// PaymentAccount is an abstract class that is used as a base for such classes as CreditCard, 
    /// CashCard, GiftCertificate and PuchaseOrder.
    /// </summary>
    /// <remarks>
    /// PaymentAccount is used by the Payment class to define the details of the payment method provided 
    /// for the order. As such it is included in the Basket through the Payments collection.
    /// Objects of the classes derived from the Payment can also be stored as part of the user profile 
    /// information. For example, a user profile has the CreditCards collection.
    /// </remarks>
    public class PaymentAccount : ICommerceEntity
    {
        /// <summary>
        /// defines the model name for this commerce entity
        /// </summary>
        public const string ModelNameDefinition = "PaymentAccount";

        /// <summary>
        /// The commerce entity.
        /// </summary>
        private CommerceEntity commerceEntity;

        /// <summary>
        /// Initializes a new instance of the <see cref="PaymentAccount"/> class.
        /// </summary>
        public PaymentAccount() : base()
        {
            this.commerceEntity = new CommerceEntity(PaymentAccount.ModelNameDefinition);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PaymentAccount"/> class.
        /// </summary>
        /// <param name="commerceEntity">The instances commerce entity</param>
        public PaymentAccount(CommerceEntity commerceEntity)
        {
            this.commerceEntity = commerceEntity;
        }

        #region ICommerceEntity Members

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id of the entity.</value>
        public string Id
        {
            get { return this.commerceEntity.Id; }
            set { this.commerceEntity.Id = value; }
        }

        /// <summary>
        /// Gets or sets the type name of this object instance
        /// <remarks>Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type</remarks>
        /// </summary>
        /// <value></value>
        public string ModelName
        {
            get { return this.commerceEntity.ModelName; }
            set { this.commerceEntity.ModelName = value; }
        }

        /// <summary>
        /// Gets or sets this objects collection of Properties and their corresponding values
        /// </summary>
        /// <value></value>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Collection setting is required")]
        public CommercePropertyCollection Properties
        {
            get { return this.commerceEntity.Properties; }
            set { this.commerceEntity.Properties = value; }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the address identifier for the billing.
        /// </summary>
        /// <value>The billing address id.</value>
        public string BillingAddressId
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.BillingAddressId) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.BillingAddressId, value); }
        }

        /// <summary>
        /// Gets or sets the customer's name as it appears on the credit card or purchase order.
        /// </summary>
        /// <value>The name of the customer.</value>
        public string CustomerName
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.CustomerName) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.CustomerName, value); }
        }

        /// <summary>
        /// Gets or sets the display name of the payment method.
        /// </summary>
        /// <value>The display name.</value>
        /// <remarks>This is the name that is used in the UI to help to identify the payment for
        /// the user, Ex.: "My personal American Express, "Company's MasterCard, etc
        /// </remarks>
        public string DisplayName
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.DisplayName) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.DisplayName, value); }
        }

        /// <summary>
        /// Gets or sets the system's configured payment method.
        /// </summary>
        /// <value>The payment method.</value>
        public CommerceRelationship PaymentMethod
        {
            get { return this.commerceEntity.GetPropertyValue(RelationshipName.PaymentMethod) as CommerceRelationship; }
            set { this.commerceEntity.SetPropertyValue(RelationshipName.PaymentMethod, value); }
        }

        /// <summary>
        /// Gets or sets the commerce entity
        /// </summary>
        protected CommerceEntity CommerceEntity
        {
            get
            {
                return this.commerceEntity;
            }

            set
            {
                this.commerceEntity = value;
            }
        }

        #endregion Properties

        #region Implicit operators
        /// <summary>
        /// Performs an implicit conversion from <see cref="Microsoft.Commerce.Contracts.CommerceEntity"/> to <see cref="CashCard"/>.
        /// </summary>
        /// <param name="commerceEntity">The commerce entity.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator PaymentAccount(CommerceEntity commerceEntity)
        {
            System.Diagnostics.Debug.Assert(
                PaymentAccount.ModelNameDefinition.Equals(commerceEntity.ModelName) ||
                CreditCard.ModelNameDefinition.Equals(commerceEntity.ModelName),
                "Unexpected model name");
            return new PaymentAccount(commerceEntity);
        }
        #endregion

        /// <summary>
        /// Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type using <see cref="ModelName"/>
        /// </summary>
        /// <returns>This instances base type</returns>
        public CommerceEntity ToCommerceEntity()
        {
            return this.commerceEntity;
        }

        #region Property key names

        /// <summary>
        /// Names of the properties exposed by this commerce entity.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Needed for external access"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Cannot make it private as it cannot be derived from")]
        public class PropertyName : CommerceEntity.PropertyName
        {
            /// <summary>
            /// The name of the BillingAddressId property for a PaymentAccount.
            /// </summary>
            public const string BillingAddressId = "BillingAddressId";

            /// <summary>
            /// The name of the CustomerName property for a PaymentAccount.
            /// </summary>
            public const string CustomerName = "CustomerName";

            /// <summary>
            /// The name of the PaymentMethod property for a PaymentAccount.
            /// </summary>
            public const string PaymentMethod = "PaymentMethod";

            /// <summary>
            /// The name of the DisplayName property for a PaymentAccount.
            /// </summary>
            public const string DisplayName = "DisplayName";
        }

        #endregion

        /// <summary>
        /// Class defining Properties of Items that may be related to a PaymentAccount.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "Required because of API specification (i.e. DataContract design)")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Needed for external access"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Cannot make it private as it cannot be derived from")]
        public class RelationshipName
        {
            /// <summary>
            /// The name of the PaymentMethod relationship for a PaymentAccount.
            /// </summary>
            public const string PaymentMethod = "PaymentMethod";
        }
    }
}
